#include "fxcc/core/graph/opengl3/Texture.h"
#include "fxcc/core/graph/opengl3/RenderStates.h"

#include <gli/texture2d.hpp>
#include <gli/convert.hpp>
#include <gli/generate_mipmaps.hpp>

using namespace fxcc::graph::opengl3;

void Texture::Bind() const
{
	glBindTexture(GetTarget(), m_Id);
}

void Texture::Mipmap() const
{
	Bind();
	glGenerateMipmap(GetTarget());
}

void fxcc::graph::opengl3::Texture::SetSampler(const fxcc::graph::common::SamplerType& sampler)
{
	auto& rs = fxcc::graph::opengl3::RenderStates::Inst();
	rs.SetSampler(m_Target, sampler);
}

void Texture::Create()
{
	glDeleteTextures(1, &m_Id);
	glGenTextures(1, &m_Id);
}

void Texture::Delete()
{
	glDeleteTextures(1, &m_Id);
}

bool fxcc::graph::opengl3::Texture::LoadImage(fxcc::graph::common::ImageMipmap::MipMapData& imageData, int target, int level, int nrComponent, int hdr) const
{
	Bind();
	glGetTexLevelParameteriv(target, 0, GL_TEXTURE_WIDTH, &imageData.m_Width);
	glGetTexLevelParameteriv(target, 0, GL_TEXTURE_HEIGHT, &imageData.m_Height);
	glGetTexLevelParameteriv(target, 0, GL_TEXTURE_DEPTH, &imageData.m_Depth);

	imageData.m_Width >>= level;
	imageData.m_Height >>= level;
	imageData.m_HDR = hdr;
	imageData.m_NrComponent = nrComponent;
	imageData.InitData();

	auto& rs = fxcc::graph::opengl3::RenderStates::Inst();
	int fmt = rs.GetFormat(imageData.m_NrComponent);

	glGetTexImage(target, level, fmt, imageData.m_HDR ? GL_FLOAT : GL_UNSIGNED_BYTE, imageData.GetData2());
	return imageData.m_Width;
}

fxcc::graph::common::ImageMipmap::MipMapData fxcc::graph::opengl3::Texture::GetImage2D(int target, int level, int nrComponent, int hdr) const
{
	fxcc::graph::common::ImageMipmap::MipMapData imageData;
	LoadImage(imageData, target, level, nrComponent, hdr);
	return imageData;
}

void fxcc::graph::opengl3::Texture::TexImage2D(int target, int level, const fxcc::graph::common::ImageMipmap::MipMapData& levelData) const
{
	auto& rs = RenderStates::Inst();
	int numChannels = levelData.m_NrComponent;
	int hdr = levelData.m_HDR;
	int width = levelData.m_Width;
	int height = levelData.m_Height;
	auto data = levelData.GetData();

	int format = rs.GetFormat(numChannels);
	int internalFormat = rs.GetInternalFomart(numChannels, hdr);
	glTexImage2D(target, level, internalFormat, width, height, 0, format, hdr ? GL_FLOAT : GL_UNSIGNED_BYTE, data);

}

unsigned int Texture::GetTarget() const
{
	return m_Target;
}
